home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / net / omniORB-2.5.0-src.tar.gz / omniORB-2.5.0-src.tar / omniORB_2.5.0 / include / omnithread.h.00 < prev   
Text File  |  1998-04-12  |  13KB  |  469 lines

  1. //                Package : omnithread
  2. // omnithread.h            Created : 7/94 tjr
  3. //
  4. //    Copyright (C) 1994,1995,1996, 1997 Olivetti & Oracle Research Laboratory
  5. //
  6. //    This file is part of the omnithread library
  7. //
  8. //    The omnithread library is free software; you can redistribute it and/or
  9. //    modify it under the terms of the GNU Library General Public
  10. //    License as published by the Free Software Foundation; either
  11. //    version 2 of the License, or (at your option) any later version.
  12. //
  13. //    This library is distributed in the hope that it will be useful,
  14. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16. //    Library General Public License for more details.
  17. //
  18. //    You should have received a copy of the GNU Library General Public
  19. //    License along with this library; if not, write to the Free
  20. //    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
  21. //    02111-1307, USA
  22. //
  23.  
  24. //
  25. // Interface to OMNI thread abstraction.
  26. //
  27. // This file declares classes for threads and synchronisation objects
  28. // (mutexes, condition variables and counting semaphores).
  29. //
  30. // Wherever a seemingly arbitrary choice has had to be made as to the interface
  31. // provided, the intention here has been to be as POSIX-like as possible.  This
  32. // is why there is no semaphore timed wait, for example.
  33. //
  34.  
  35. #ifndef __omnithread_h_
  36. #define __omnithread_h_
  37.  
  38. #ifndef NULL
  39. #define NULL (void*)0
  40. #endif
  41.  
  42. class omni_mutex;
  43. class omni_condition;
  44. class omni_semaphore;
  45. class omni_thread;
  46.  
  47. //
  48. // OMNI_THREAD_EXPOSE can be defined as public or protected to expose the
  49. // implementation class - this may be useful for debugging.  Hopefully this
  50. // won't change the underlying structure which the compiler generates so that
  51. // this can work without recompiling the library.
  52. //
  53.  
  54. #ifndef OMNI_THREAD_EXPOSE
  55. #define OMNI_THREAD_EXPOSE private
  56. #endif
  57.  
  58.  
  59. //
  60. // Include implementation-specific header file.
  61. //
  62. // This must define 4 CPP macros of the form OMNI_x_IMPLEMENTATION for mutex,
  63. // condition variable, semaphore and thread.  Each should define any
  64. // implementation-specific members of the corresponding classes.
  65. //
  66.  
  67.  
  68. #if defined(__arm__) && defined(__atmos__)
  69. #include <omnithread/posix.h>
  70.  
  71. #elif defined(__alpha__) && defined(__osf1__)
  72. #include <omnithread/posix.h>
  73.  
  74. #elif defined(__powerpc__) && defined(__aix__)
  75. #include <omnithread/posix.h>
  76.  
  77. #elif defined(__hpux__)
  78. #include <omnithread/posix.h>
  79.  
  80. #elif defined(__WIN32__)
  81. #include <omnithread/nt.h>
  82.  
  83. #ifdef _MSC_VER
  84.  
  85. // Using MSVC++ to compile. If compiling library as a DLL,
  86. // define _OMNITHREAD_DLL. If compiling as a statuc library, define
  87. // _WINSTATIC
  88. // If compiling an application that is to be statically linked to omnithread,
  89. // define _WINSTATIC (if the application is  to be dynamically linked, 
  90. // there is no need to define any of these macros).
  91.  
  92. #if defined (_OMNITHREAD_DLL) && defined(_WINSTATIC)
  93. #error "Both _OMNITHREAD_DLL and _WINSTATIC are defined."
  94. #elif defined(_OMNITHREAD_DLL)
  95. #define _OMNITHREAD_NTDLL_ __declspec(dllexport)
  96. #elif !defined(_WINSTATIC)
  97. #define _OMNITHREAD_NTDLL_ __declspec(dllimport)
  98. #elif defined(_WINSTATIC)
  99. #define _OMNITHREAD_NTDLL_
  100. #endif
  101.  // _OMNITHREAD_DLL && _WINSTATIC
  102.  
  103. #else
  104.  
  105. // Not using MSVC++ to compile
  106. #define _OMNITHREAD_NTDLL_
  107.  
  108. #endif
  109.  // _MSC_VER
  110.  
  111. #elif defined(__sunos__) && (__OSVERSION__ == 5)
  112. #ifdef UsePthread
  113. #include <omnithread/posix.h>
  114. #else
  115. #include <omnithread/solaris.h>
  116. #endif
  117.  
  118. #elif defined(__linux__)
  119. #include <omnithread/posix.h>
  120.  
  121. #elif defined(__nextstep__)
  122. #include <omnithread/mach.h>
  123.  
  124. #elif defined(__VMS)
  125. #include <omnithread/posix.h>
  126.  
  127. #else
  128. #error "No implementation header file"
  129. #endif
  130.  
  131. #if !defined(__WIN32__)
  132. #define _OMNITHREAD_NTDLL_
  133. #endif
  134.  
  135. #if (!defined(OMNI_MUTEX_IMPLEMENTATION) || \
  136.      !defined(OMNI_CONDITION_IMPLEMENTATION) || \
  137.      !defined(OMNI_SEMAPHORE_IMPLEMENTATION) || \
  138.      !defined(OMNI_THREAD_IMPLEMENTATION))
  139. #error "Implementation header file incomplete"
  140. #endif
  141.  
  142.  
  143. //
  144. // This exception is thrown in the event of a fatal error.
  145. //
  146.  
  147. class _OMNITHREAD_NTDLL_ omni_thread_fatal {
  148. public:
  149.     int error;
  150.     omni_thread_fatal(int e = 0) : error(e) {}
  151. };
  152.  
  153.  
  154. //
  155. // This exception is thrown when an operation is invoked with invalid
  156. // arguments.
  157. //
  158.  
  159. class _OMNITHREAD_NTDLL_ omni_thread_invalid {};
  160.  
  161.  
  162. ///////////////////////////////////////////////////////////////////////////
  163. //
  164. // Mutex
  165. //
  166. ///////////////////////////////////////////////////////////////////////////
  167.  
  168. class _OMNITHREAD_NTDLL_ omni_mutex {
  169.  
  170. public:
  171.     omni_mutex(void);
  172.     ~omni_mutex(void);
  173.  
  174.     void lock(void);
  175.     void unlock(void);
  176.     void acquire(void) { lock(); }
  177.     void release(void) { unlock(); }
  178.     // the names lock and unlock are preferred over acquire and release
  179.     // since we are attempting to be as POSIX-like as possible.
  180.  
  181.     friend class omni_condition;
  182.  
  183. OMNI_THREAD_EXPOSE:
  184.     OMNI_MUTEX_IMPLEMENTATION
  185. };
  186.  
  187. //
  188. // As an alternative to:
  189. // {
  190. //   mutex.lock();
  191. //   .....
  192. //   mutex.unlock();
  193. // }
  194. //
  195. // you can use a single instance of the omni_mutex_lock class:
  196. //
  197. // {
  198. //   omni_mutex_lock l(mutex);
  199. //   ....
  200. // }
  201. //
  202. // This has the advantage that mutex.unlock() will be called automatically
  203. // when an exception is thrown.
  204. //
  205.  
  206. class _OMNITHREAD_NTDLL_ omni_mutex_lock {
  207.     omni_mutex& mutex;
  208. public:
  209.     omni_mutex_lock(omni_mutex& m) : mutex(m) { mutex.lock(); }
  210.     ~omni_mutex_lock(void) { mutex.unlock(); }
  211. };
  212.  
  213.  
  214. ///////////////////////////////////////////////////////////////////////////
  215. //
  216. // Condition variable
  217. //
  218. ///////////////////////////////////////////////////////////////////////////
  219.  
  220. class _OMNITHREAD_NTDLL_ omni_condition {
  221.  
  222.     omni_mutex* mutex;
  223.  
  224. public:
  225.     omni_condition(omni_mutex* m);
  226.     // constructor must be given a pointer to an existing mutex. The
  227.     // condition variable is then linked to the mutex, so that there is an
  228.     // implicit unlock and lock around wait() and timed_wait().
  229.  
  230.     ~omni_condition(void);
  231.  
  232.     void wait(void);
  233.     // wait for the condition variable to be signalled.  The mutex is
  234.     // implicitly released before waiting and locked again after waking up.
  235.     // If wait() is called by multiple threads, a signal may wake up more
  236.     // than one thread.  See POSIX threads documentation for details.
  237.  
  238.     int timedwait(unsigned long secs, unsigned long nanosecs = 0);
  239.     // timedwait() is given an absolute time to wait until.  To wait for a
  240.     // relative time from now, use omni_thread::get_time. See POSIX threads
  241.     // documentation for why absolute times are better than relative.
  242.     // Returns 1 (true) if successfully signalled, 0 (false) if time
  243.     // expired.
  244.  
  245.     void signal(void);
  246.     // if one or more threads have called wait(), signal wakes up at least
  247.     // one of them, possibly more.  See POSIX threads documentation for
  248.     // details.
  249.  
  250.     void broadcast(void);
  251.     // broadcast is like signal but wakes all threads which have called
  252.     // wait().
  253.  
  254. OMNI_THREAD_EXPOSE:
  255.     OMNI_CONDITION_IMPLEMENTATION
  256. };
  257.  
  258.  
  259. ///////////////////////////////////////////////////////////////////////////
  260. //
  261. // Counting semaphore
  262. //
  263. ///////////////////////////////////////////////////////////////////////////
  264.  
  265. class _OMNITHREAD_NTDLL_ omni_semaphore {
  266.  
  267. public:
  268.     omni_semaphore(unsigned int initial = 1);
  269.     ~omni_semaphore(void);
  270.  
  271.     void wait(void);
  272.     // if semaphore value is > 0 then decrement it and carry on. If it's
  273.     // already 0 then block.
  274.  
  275.     int trywait(void);
  276.     // if semaphore value is > 0 then decrement it and return 1 (true).
  277.     // If it's already 0 then return 0 (false).
  278.  
  279.     void post(void);
  280.     // if any threads are blocked in wait(), wake one of them up. Otherwise
  281.     // increment the value of the semaphore.
  282.  
  283. OMNI_THREAD_EXPOSE:
  284.     OMNI_SEMAPHORE_IMPLEMENTATION
  285. };
  286.  
  287. //
  288. // A helper class for semaphores, similar to omni_mutex_lock above.
  289. //
  290.  
  291. class _OMNITHREAD_NTDLL_ omni_semaphore_lock {
  292.     omni_semaphore& sem;
  293. public:
  294.     omni_semaphore_lock(omni_semaphore& s) : sem(s) { sem.wait(); }
  295.     ~omni_semaphore_lock(void) { sem.post(); }
  296. };
  297.  
  298.  
  299. ///////////////////////////////////////////////////////////////////////////
  300. //
  301. // Thread
  302. //
  303. ///////////////////////////////////////////////////////////////////////////
  304.  
  305. class _OMNITHREAD_NTDLL_ omni_thread {
  306.  
  307. public:
  308.  
  309.     enum priority_t {
  310.     PRIORITY_LOW,
  311.     PRIORITY_NORMAL,
  312.     PRIORITY_HIGH
  313.     };
  314.  
  315.     enum state_t {
  316.     STATE_NEW,        // thread object exists but thread hasn't
  317.                 // started yet.
  318.     STATE_RUNNING,        // thread is running.
  319.     STATE_TERMINATED    // thread has terminated but storage has not
  320.                 // been reclaimed (i.e. waiting to be joined).
  321.     };
  322.  
  323.     //
  324.     // Constructors set up the thread object but the thread won't start until
  325.     // start() is called. The create method can be used to construct and start
  326.     // a thread in a single call.
  327.     //
  328.  
  329.     omni_thread(void (*fn)(void*), void* arg = NULL,
  330.         priority_t pri = PRIORITY_NORMAL);
  331.     omni_thread(void* (*fn)(void*), void* arg = NULL,
  332.         priority_t pri = PRIORITY_NORMAL);
  333.     // these constructors create a thread which will run the given function
  334.     // when start() is called.  The thread will be detached if given a
  335.     // function with void return type, undetached if given a function
  336.     // returning void*. If a thread is detached, storage for the thread is
  337.     // reclaimed automatically on termination. Only an undetached thread
  338.     // can be joined.
  339.  
  340.     void start(void);
  341.     // start() causes a thread created with one of the constructors to
  342.     // start executing the appropriate function.
  343.  
  344. protected:
  345.  
  346.     omni_thread(void* arg = NULL, priority_t pri = PRIORITY_NORMAL);
  347.     // this constructor is used in a derived class.  The thread will
  348.     // execute the run() or run_undetached() member functions depending on
  349.     // whether start() or start_undetached() is called respectively.
  350.  
  351.     void start_undetached(void);
  352.     // can be used with the above constructor in a derived class to cause
  353.     // the thread to be undetached.  In this case the thread executes the
  354.     // run_undetached member function.
  355.  
  356.     virtual ~omni_thread(void);
  357.     // destructor cannot be called by user (except via a derived class).
  358.     // Use exit() or cancel() instead. This also means a thread object must
  359.     // be allocated with new - it cannot be statically or automatically
  360.     // allocated. The destructor of a class that inherits from omni_thread
  361.     // shouldn't be public either (otherwise the thread object can be
  362.     // destroyed while the underlying thread is still running).
  363.  
  364. public:
  365.  
  366.     void join(void**);
  367.     // join causes the calling thread to wait for another's completion,
  368.     // putting the return value in the variable of type void* whose address
  369.     // is given (unless passed a null pointer). Only undetached threads
  370.     // may be joined. Storage for the thread will be reclaimed.
  371.  
  372.     void set_priority(priority_t);
  373.     // set the priority of the thread.
  374.  
  375.     static omni_thread* create(void (*fn)(void*), void* arg = NULL,
  376.                    priority_t pri = PRIORITY_NORMAL);
  377.     static omni_thread* create(void* (*fn)(void*), void* arg = NULL,
  378.                    priority_t pri = PRIORITY_NORMAL);
  379.     // create spawns a new thread executing the given function with the
  380.     // given argument at the given priority. Returns a pointer to the
  381.     // thread object. It simply constructs a new thread object then calls
  382.     // start.
  383.  
  384.     static void exit(void* return_value = NULL);
  385.     // causes the calling thread to terminate.
  386.  
  387.     static omni_thread* self(void);
  388.     // returns the calling thread's omni_thread object.
  389.  
  390.     static void yield(void);
  391.     // allows another thread to run.
  392.  
  393.     static void sleep(unsigned long secs, unsigned long nanosecs = 0);
  394.     // sleeps for the given time.
  395.  
  396.     static void get_time(unsigned long* abs_sec, unsigned long* abs_nsec,
  397.              unsigned long rel_sec = 0, unsigned long rel_nsec=0);
  398.     // calculates an absolute time in seconds and nanoseconds, suitable for
  399.     // use in timed_waits on condition variables, which is the current time
  400.     // plus the given relative offset.
  401.  
  402. private:
  403.  
  404.     virtual void run(void* arg) {}
  405.     virtual void* run_undetached(void* arg) { return NULL; }
  406.     // can be overridden in a derived class.  When constructed using the
  407.     // the constructor omni_thread(void*, priority_t), these functions are
  408.     // called by start() and start_undetached() respectively.
  409.  
  410.     void common_constructor(void* arg, priority_t pri, int det);
  411.     // implements the common parts of the constructors.
  412.  
  413.     omni_mutex mutex;
  414.     // used to protect any members which can change after construction,
  415.     // i.e. the following 2 members:
  416.  
  417.     state_t _state;
  418.     priority_t _priority;
  419.  
  420.     static omni_mutex* next_id_mutex;
  421.     static int next_id;
  422.     int _id;
  423.  
  424.     void (*fn_void)(void*);
  425.     void* (*fn_ret)(void*);
  426.     void* thread_arg;
  427.     int detached;
  428.  
  429. public:
  430.  
  431.     priority_t priority(void) {
  432.  
  433.     // return this thread's priority.
  434.  
  435.     omni_mutex_lock l(mutex);
  436.     return _priority;
  437.     }
  438.  
  439.     state_t state(void) {
  440.  
  441.     // return thread state (invalid, new, running or terminated).
  442.  
  443.     omni_mutex_lock l(mutex);
  444.     return _state;
  445.     }
  446.  
  447.     int id(void) { return _id; }
  448.     // return unique thread id within the current process.
  449.  
  450.  
  451.     // This class plus the instance of it declared below allows us to execute
  452.     // some initialisation code before main() is called.
  453.  
  454.     class _OMNITHREAD_NTDLL_ init_t {
  455.     static int count;
  456.     public:
  457.     init_t(void);
  458.     };
  459.  
  460.     friend class init_t;
  461.  
  462. OMNI_THREAD_EXPOSE:
  463.     OMNI_THREAD_IMPLEMENTATION
  464. };
  465.  
  466. static omni_thread::init_t omni_thread_init;
  467.  
  468. #endif
  469.